home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #include <stdarg.h>
- #include <ctype.h>
- #include "../misc/misc.h"
- #include "internal.h"
-
- // This table indicates the correspondance for the first
- // string and second string of the MSG_B macro.
- static char *tblang;
-
- #ifdef UNIX
- #include <limits.h>
- #define MAXIMUM_PATH PATH_MAX
- #else
- #define MAXIMUM_PATH 128
- #endif
-
- struct READINFO{
- int noline;
- char buf[1000];
- FILE *fin;
- };
-
- /*
- Print an error message in a popup
- Stubs to avoid linking the world
- */
- void xconf_error (const char *msg, ...)
- {
- va_list list;
- va_start (list,msg);
- vfprintf (stderr,msg,list);
- va_end (list);
- }
-
- struct {
- const char *fname;
- int noline;
- int nberr;
- int showname;
- int showline; // First error for a context
- }err;
- /*
- Record basic info about errors
- */
- static void msgscan_errset (const char *fname, int noline)
- {
- if (err.fname == NULL || strcmp(err.fname,fname)!=0){
- err.showname = 1;
- }
- err.fname = fname;
- err.noline = noline;
- err.showline = 1;
- }
-
- /*
- Display an error message with context
- */
- static void msgscan_err (const char *ctl, ...)
- {
- va_list list;
- va_start (list,ctl);
- if (err.showname){
- fprintf (stderr,"ERR: In file %s\n",err.fname);
- err.showname = 0;
- }
- if (err.showline){
- fprintf (stderr,"\t\tstarting on line %d\n",err.noline);
- err.showline = 0;
- }
- fprintf (stderr,"\t\t\t");
- vfprintf (stderr,ctl,list);
- va_end (list);
- }
-
- static int msgscan_read (READINFO &inf, int signal_err)
- {
- int ret = fgets_cont (inf.buf,sizeof(inf.buf)-1,inf.fin);
- inf.noline++;
- if (ret == -1 && signal_err){
- msgscan_err ("EOF while parsing\n");
- }
- return ret;
- }
-
-
-
- static char *scan_copyid (const char * pt, char id[])
- {
- pt = str_skip (pt);
- char *ptid = id;
- while (isalpha(*pt) || isdigit(*pt) || *pt == '_'){
- *ptid++ = *pt++;
- }
- *ptid = '\0';
- return (char*)pt;
- }
-
-
- static int scan_parseid (char * &pt, char id[])
- {
- int ret = -1;
- pt = scan_copyid (pt,id);
- if (id[0] != '\0'){
- if (isdigit(id[0])){
- msgscan_err ("Invalid id %s\n",id);
- }else{
- ret = 0;
- }
- }
- return ret;
- }
-
-
- /*
- Extract a single string from a C source.
- */
- static int scan_parse1str (char * &pt, SSTRING &s)
- {
- int ret = -1;
- pt = str_skip (pt);
- if (*pt != '"'){
- msgscan_err ("Expected an openning \"\n");
- }else{
- pt++;
- char *start = pt;
- while (1){
- if (*pt == '\0'){
- msgscan_err ("Expected an ending \"\n");
- break;
- }else if (*pt == '"'){
- ret = 0;
- *pt++ = '\0';
- s.append (start);
- break;
- }else if (*pt == '\\'){
- pt++;
- if (*pt != '\0') pt++;
- }else{
- pt++;
- }
-
- }
- }
- return ret;
- }
- /*
- Extract a string (or sequence) from a C source. A string may be made
- of several strings concatenated and potentially spreaded on
- several lines.
- */
- static int scan_parsestr (
- char * &pt,
- SSTRING &s,
- READINFO &inf)
- {
- int ret = -1;
- s.setfrom ("");
- while (1){
- pt = str_skip (pt);
- if (*pt == '\0'){
- if (msgscan_read(inf,1)==-1){
- break;
- }
- pt = inf.buf;
- }else if (*pt != '"'){
- if (ret == -1){
- msgscan_err ("Expected an openning \"\n");
- }
- break;
- }else if (scan_parse1str(pt,s)==-1){
- ret = -1;
- break;
- }else{
- // One string was seen, looking for others
- ret = 0;
- }
- }
- return ret;
- }
-
- /*
- Parse a MSG_x() macro to extract the ID and the strings
- Return the pointer after the closing parenthese.
- */
- static char *scan_parse(
- char *pt,
- TR_STRINGS &tr,
- READINFO &inf,
- int nbsreq) // Number of strings expected
- {
- /* #Specification: translation / message / encoding in source
- Messages are created in C (C++) source files and
- extracted with a utility (msgscan). A message is
- defined like this
-
- #
- // This is a message without translation
- MSG_U(msgid,"message's text")
- // This is a message with a proposed translation
- MSG_B(msgid,"message's text","Texte du message")
- #
-
- msgid is a unique identifier generally composed of
- letters and number. It must respected lexical
- convention for macros (as it will be #defined)
- */
- pt = str_skip (pt);
- int last_nberr = err.nberr;
- if (pt[0] == '('){
- char id[100];
- if (scan_parseid(++pt,id)!=-1){
- SSTRING tbs[2];
- int nbs = 0;
- while (1){
- pt = str_skip (pt);
- if (pt[0] == '\0'){
- // We must refill the buffer
- if (msgscan_read (inf,1)==-1){
- break;
- }
- pt = inf.buf;
- }else if (*pt == ')'){
- pt++;
- break;
- }else if (*pt != ','){
- msgscan_err ("expected comma after id\n");
- break;
- }else if (nbs == nbsreq){
- msgscan_err ("Too many strings\n");
- break;
- }else if (scan_parsestr(++pt,tbs[nbs],inf)==0){
- nbs++;
- }else{
- break;
- }
- }
- if (err.nberr == last_nberr){
- if (nbs != nbsreq){
- msgscan_err ("Not enough strings supplied\n");
- }else{
- TR_STRING *t = tr.getitem(id);
- if (t == NULL){
- t = new TR_STRING (id);
- tr.add (t);
- }
- if (t->was_changed()){
- msgscan_err ("Duplicate translation id %s\n"
- ,id);
- const char *ori = t->getorigin();
- msgscan_err (" It was defined in %s\n",ori);
- msgscan_err (" Previous definition was \"%s\"\n"
- ,t->getmsg(tblang[0]));
- msgscan_err (" New definition is \"%s\"\n",tbs[0].get());
- }else{
- t->setorigin (err.fname);
- for (int i=0; i<nbs; i++){
- t->settranslation (tblang[i]
- ,tbs[i].get());
- }
- }
- }
- }
- }
- }else{
- msgscan_err("Expected (\n");
- }
- if (err.nberr != last_nberr){
- // We skip this line to avoid falling always on the same
- // error.
- while (*pt != '\0') pt++;
- }
- return pt;
- }
-
-
-
- /*
- Locate all messages in a source file and update the
- dictionary.
- Return -1 if any error
- */
- int scan_one (const char *fname, TR_STRINGS &tr)
- {
- int ret = -1;
- READINFO inf;
- inf.noline = 0;
- inf.fin = vfopen (fname,"r");
- if (inf.fin == NULL){
- fprintf (stderr,"Can't open file %s (%s)\n",fname
- ,strerror(errno));
- }else{
- ret = 0;
- while (msgscan_read (inf,0)!=-1){
- char *pt = inf.buf;
- // Maybe more than one message on the line
- while (1){
- pt = strstr (pt,"MSG");
- if (pt != NULL){
- char verb[1000];
- pt = scan_copyid (pt,verb);
- if (strcmp(verb,"MSG_U")==0){
- msgscan_errset (fname,inf.noline);
- pt = scan_parse (pt,tr,inf,1);
- }else if (strcmp(verb,"MSG_B")==0){
- msgscan_errset (fname,inf.noline);
- pt = scan_parse (pt,tr,inf,2);
- }
- }else{
- break;
- }
- }
- }
- }
- return ret;
- }
-
- #if 0
- int scan_vone (const char *fname, TR_STRINGS &tr)
- {
- int ret = 0;
- char *tb[1000];
- int nb = vdir_getlistp (fname,tb,1000);
- for (int i=0; i<nb; i++){
- ret |= scan_one (tb[i],tr);
- }
- return ret;
- }
- #endif
- static void usage()
- {
- fprintf (stderr,
- "msgscan 1.0\n"
- "msgscan sysname dictionary header lang_letters source source ...\n"
- "\n"
- "Update the dictionary file with source (C C++ source)\n"
- "The file dictionary will be the ascii dictionary\n"
- "the file \"header\" will be produced\n"
- "and must be included in every source files using the dictionary\n"
- "\n"
- "lang_letters is a string of 2 letters use to tag the first and\n"
- "second string extracted from an MSG_U/MSG_B macro\n"
- "\n"
- "Normal usage for the linuxconf project\n"
- "\tmsgscan netconf ../messages/sources/netconf.dic netconf.m EF *.c\n"
- );
- }
-
- int main (int argc, char *argv[])
- {
- int ret = -1;
- if (argc < 6){
- usage();
- }else{
- TR_STRINGS tr;
- const char *sys = argv[1];
- const char *pathdict = argv[2];
- const char *pathincl = argv[3];
- tblang = argv[4];
- tr.read (pathdict);
- tr.deltranslation (tblang[0]);
- tr.deltranslation (tblang[1]);
- ret = 0;
- for (int i=5; i<argc; i++){
- ret |= scan_one (argv[i],tr);
- }
- if (ret == 0){
- char path[MAXIMUM_PATH];
- sprintf (path,"%s.old",pathdict);
- rename (pathdict,path);
- tr.write (pathdict);
- tr.writeh (sys,pathincl);
- tr.showold (tblang[0]);
- }
- }
- return ret;
- }
-
-